﻿using System.Collections.ObjectModel;
using System.IO;
using System.Windows.Media;
using FileTransfer.Client;
using FileTransfer.Client.Http.Model;
using FileTransfer.Client.Utils;
using FileTransferDesktop.Extensions;
using FileTransferDesktop.Services;
using LiveChartsCore;
using LiveChartsCore.Defaults;
using LiveChartsCore.Drawing;
using LiveChartsCore.Kernel.Events;
using LiveChartsCore.Kernel.Sketches;
using LiveChartsCore.Measure;
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore.SkiaSharpView.Painting;
using Microsoft.Extensions.DependencyInjection;
using SkiaSharp;
using Wpf.Ui;
using Wpf.Ui.Appearance;

namespace FileTransferDesktop.ViewModels.Pages;

public partial class HistoryItem : ObservableObject
{
    [ObservableProperty]
    private string _name = string.Empty;

    [ObservableProperty]
    private string _status = string.Empty;

    [ObservableProperty]
    private DateTime _time = DateTime.MinValue;

    [ObservableProperty]
    private string _size = string.Empty;
}

public partial class DashboardViewModel : ObservableObject
{
    private readonly ApiClient _apiClient;
    private readonly System.IServiceProvider _serviceProvider;
    private bool _isDown = false;
    private readonly ObservableCollection<ObservablePoint> _downloadValues = [];
    private readonly ObservableCollection<ObservablePoint> _uploadValues = [];
    private readonly INavigationWindow _navigationWindow;
    private System.Timers.Timer? _realTimeUpdateTimer;

    // Backend data properties
    [ObservableProperty]
    private string _transferredFilesCount = "0";

    [ObservableProperty]
    private string _transferredFilesChange = "0%";

    [ObservableProperty]
    private string _totalCapacity = "0 GB";

    [ObservableProperty]
    private string _totalCapacityChange = "0%";

    [ObservableProperty]
    private string _activeShares = "0";

    [ObservableProperty]
    private string _activeSharesChange = "0%";

    // Dynamic properties for change indicators
    [ObservableProperty]
    private string _transferredFilesChangeText = "0%";

    [ObservableProperty]
    private string _transferredFilesChangeColor = "#6B7280";

    [ObservableProperty]
    private string _transferredFilesChangeIcon = "Subtract16";

    [ObservableProperty]
    private string _totalCapacityChangeText = "0%";

    [ObservableProperty]
    private string _totalCapacityChangeColor = "#6B7280";

    [ObservableProperty]
    private string _totalCapacityChangeIcon = "Subtract16";

    [ObservableProperty]
    private string _activeSharesChangeText = "0%";

    [ObservableProperty]
    private string _activeSharesChangeColor = "#6B7280";

    [ObservableProperty]
    private string _activeSharesChangeIcon = "Subtract16";

    [ObservableProperty]
    private double _storageUtilizationPercentage = 0.0;

    [ObservableProperty]
    private string _storageUtilizationText = "0 GB / 0 GB";

    [ObservableProperty]
    private SolidColorPaint _legendTextPaint = null!;

    public DashboardViewModel(IServiceProvider serviceProvider, INavigationWindow navigationWindow)
    {
        _serviceProvider = serviceProvider;
        _apiClient = serviceProvider.CreateApiClient();
        _navigationWindow = navigationWindow;

        // 初始化图例文本颜色
        UpdateLegendTextPaint();

        // Initialize with local data
        InitializeLocalData();

        // Initialize chart series with default data
        InitializeChartSeries();

        // Initialize axes and layout
        InitializeChartLayout();

        // Load backend data asynchronously
        _ = Task.Run(async () => await LoadDashboardDataAsync());

        // Initialize network connectivity detection
        _ = Task.Run(async () => await InitializeNetworkStatus());

        // 监听主题变化并更新图表颜色
        ApplicationThemeManager.Changed += OnApplicationThemeChanged;
    }

    private void OnApplicationThemeChanged(
        ApplicationTheme currentApplicationTheme,
        Color systemAccent
    )
    {
        UpdateLegendTextPaint();
    }

    private void UpdateLegendTextPaint()
    {
        var color = (Color)Application.Current.Resources["TextFillColorPrimary"];
        LegendTextPaint = new SolidColorPaint(new SKColor(color.R, color.G, color.B, color.A));
        // 如果饼图已经创建，更新所有系列的标签颜色
        foreach (var series in PieSeries)
        {
            if (series is PieSeries<double> pieSeries)
            {
                pieSeries.DataLabelsPaint = LegendTextPaint;
            }
        }
    }

    private void InitializeLocalData()
    {
        var records = LocalDbService.GetAllUploads();
        var historyItems = records.Select((Func<UploadRecord, HistoryItem>)Value).Take(6).ToList();

        foreach (var task in historyItems)
        {
            RecentTransfers.Add(task);
        }

        static HistoryItem Value(UploadRecord record)
        {
            return new HistoryItem
            {
                Name = record.FileName,
                Status = record.Status,
                Time = record.UploadTime,
            };
        }

        // 加载本地文件类型分布数据
        UpdatePieSeriesFromLocalData();
    }

    private void UpdatePieSeriesFromLocalData()
    {
        // 从本地数据库获取所有文件名
        var allFileNames = LocalDbService.GetAllFileNames();

        if (allFileNames.Count == 0)
        {
            // 如果没有数据，保持默认的饼图
            return;
        }

        // 按文件类型分类统计
        var fileTypeStats = GetFileTypeStatistics(allFileNames);

        // 更新饼图数据
        UpdatePieSeriesWithStats(fileTypeStats);
    }

    private Dictionary<string, int> GetFileTypeStatistics(List<string> fileNames)
    {
        var stats = new Dictionary<string, int>
        {
            ["图片文件"] = 0,
            ["文档文件"] = 0,
            ["视频文件"] = 0,
            ["音频文件"] = 0,
            ["其他文件"] = 0,
        };

        // 定义文件扩展名映射
        var imageExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            ".jpg",
            ".jpeg",
            ".png",
            ".gif",
            ".bmp",
            ".tiff",
            ".tif",
            ".webp",
            ".svg",
            ".ico",
            ".raw",
        };

        var documentExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            ".pdf",
            ".doc",
            ".docx",
            ".xls",
            ".xlsx",
            ".ppt",
            ".pptx",
            ".txt",
            ".rtf",
            ".odt",
            ".ods",
            ".odp",
        };

        var videoExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            ".mp4",
            ".avi",
            ".mkv",
            ".mov",
            ".wmv",
            ".flv",
            ".webm",
            ".m4v",
            ".3gp",
            ".mpg",
            ".mpeg",
        };

        var audioExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            ".mp3",
            ".wav",
            ".flac",
            ".aac",
            ".ogg",
            ".wma",
            ".m4a",
            ".opus",
        };

        foreach (var fileName in fileNames)
        {
            var extension = Path.GetExtension(fileName);

            if (imageExtensions.Contains(extension))
            {
                stats["图片文件"]++;
            }
            else if (documentExtensions.Contains(extension))
            {
                stats["文档文件"]++;
            }
            else if (videoExtensions.Contains(extension))
            {
                stats["视频文件"]++;
            }
            else if (audioExtensions.Contains(extension))
            {
                stats["音频文件"]++;
            }
            else
            {
                stats["其他文件"]++;
            }
        }

        return stats;
    }

    private void UpdatePieSeriesWithStats(Dictionary<string, int> stats)
    {
        var total = stats.Values.Sum();
        if (total == 0)
            return;

        var colorMap = new Dictionary<string, SKColor[]>
        {
            ["图片文件"] = [new SKColor(0x6366F1), new SKColor(0x4F46E5)],
            ["文档文件"] = [new SKColor(0x06B6D4), new SKColor(0x0891B2)],
            ["视频文件"] = [new SKColor(0x10B981), new SKColor(0x059669)],
            ["音频文件"] = [new SKColor(0xF59E0B), new SKColor(0xD97706)],
            ["其他文件"] = [new SKColor(0x9CA3AF), new SKColor(0x6B7280)],
        };

        var newPieSeries = (
            from kvp in stats.Where(s => s.Value > 0)
            let percentage = (double)kvp.Value / total * 100
            let colors = colorMap[kvp.Key]
            select new PieSeries<double>
            {
                Name = kvp.Key,
                Values = [percentage],
                Fill = new RadialGradientPaint(colors),
                Stroke = new SolidColorPaint(SKColors.Gray, 2),
                DataLabelsPaint = LegendTextPaint,
                DataLabelsSize = 12,
                DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
                DataLabelsFormatter = point => $"{point.Model:F1}%",
                AnimationsSpeed = TimeSpan.FromMilliseconds(1000),
                HoverPushout = 8,
                ToolTipLabelFormatter = point =>
                    $"{kvp.Key}: {kvp.Value} 个文件 ({point.Model:F1}%)",
            }
        ).Cast<ISeries>().ToList();

        // 如果有数据则更新，否则保持默认
        if (newPieSeries.Count > 0)
        {
            PieSeries = newPieSeries.ToArray();
        }
    }

    private void InitializeChartSeries()
    {
        // Initialize with default trend data for smooth animation
        var r = new Random();
        var downloadTrend = 1000;
        var uploadTrend = 500;

        for (var i = 0; i < 500; i++)
        {
            _downloadValues.Add(new ObservablePoint(i, downloadTrend += r.Next(-20, 20)));
            _uploadValues?.Add(new ObservablePoint(i, uploadTrend += r.Next(-10, 10)));
        }

        // 创建渐变画笔用于线条
        var downloadGradient = new LinearGradientPaint(
            [new SKColor(0x4F, 0x46, 0xE5), new SKColor(0x06, 0xB6, 0xD4)],
            new SKPoint(0, 0),
            new SKPoint(0, 1)
        );

        var uploadGradient = new LinearGradientPaint(
            [new SKColor(0xF5, 0x9E, 0x0B), new SKColor(0xEF, 0x44, 0x44)],
            new SKPoint(0, 0),
            new SKPoint(0, 1)
        );

        // 创建填充渐变
        var downloadFillGradient = new LinearGradientPaint(
            [new SKColor(0x4F, 0x46, 0xE5, 0x40), new SKColor(0x06, 0xB6, 0xD4, 0x10)],
            new SKPoint(0, 0),
            new SKPoint(0, 1)
        );

        var uploadFillGradient = new LinearGradientPaint(
            [new SKColor(0xF5, 0x9E, 0x0B, 0x40), new SKColor(0xEF, 0x44, 0x44, 0x10)],
            new SKPoint(0, 0),
            new SKPoint(0, 1)
        );

        Series =
        [
            new LineSeries<ObservablePoint>
            {
                Name = "下载",
                Values = _downloadValues,
                GeometryStroke = new SolidColorPaint(new SKColor(0x4F, 0x46, 0xE5), 3),
                GeometryFill = new SolidColorPaint(new SKColor(0x4F, 0x46, 0xE5)),
                GeometrySize = 8,
                DataPadding = new LvcPoint(0, 1),
                Stroke = downloadGradient,
                Fill = downloadFillGradient,
                LineSmoothness = 0.8, // 平滑曲线
                AnimationsSpeed = TimeSpan.FromMilliseconds(800),
            },
            new LineSeries<ObservablePoint>
            {
                Name = "上传",
                Values = _uploadValues,
                GeometryStroke = new SolidColorPaint(new SKColor(0xF5, 0x9E, 0x0B), 3),
                GeometryFill = new SolidColorPaint(new SKColor(0xF5, 0x9E, 0x0B)),
                GeometrySize = 8,
                DataPadding = new LvcPoint(0, 1),
                Stroke = uploadGradient,
                Fill = uploadFillGradient,
                LineSmoothness = 0.8, // 平滑曲线
                AnimationsSpeed = TimeSpan.FromMilliseconds(800),
            },
        ];

        PieSeries =
        [
            new PieSeries<double>
            {
                Name = "图片文件",
                Values = [45],
                Fill = new RadialGradientPaint([new SKColor(0x6366F1), new SKColor(0x4F46E5)]),
                Stroke = new SolidColorPaint(SKColors.Gray, 2),
                DataLabelsPaint = LegendTextPaint,
                DataLabelsSize = 12,
                DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
                AnimationsSpeed = TimeSpan.FromMilliseconds(1000),
                HoverPushout = 8,
            },
            new PieSeries<double>
            {
                Name = "文档文件",
                Values = [30],
                Fill = new RadialGradientPaint([new SKColor(0x06B6D4), new SKColor(0x0891B2)]),
                Stroke = new SolidColorPaint(SKColors.Gray, 2),
                DataLabelsPaint = LegendTextPaint,
                DataLabelsSize = 12,
                DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
                AnimationsSpeed = TimeSpan.FromMilliseconds(1000),
                HoverPushout = 8,
            },
            new PieSeries<double>
            {
                Name = "视频文件",
                Values = [15],
                Fill = new RadialGradientPaint([new SKColor(0x10B981), new SKColor(0x059669)]),
                Stroke = new SolidColorPaint(SKColors.Gray, 2),
                DataLabelsPaint = LegendTextPaint,
                DataLabelsSize = 12,
                DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
                AnimationsSpeed = TimeSpan.FromMilliseconds(1000),
                HoverPushout = 8,
            },
            new PieSeries<double>
            {
                Name = "其他文件",
                Values = [10],
                Fill = new RadialGradientPaint([new SKColor(0xF59E0B), new SKColor(0xD97706)]),
                Stroke = new SolidColorPaint(SKColors.Gray, 2),
                DataLabelsPaint = LegendTextPaint,
                DataLabelsSize = 12,
                DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
                AnimationsSpeed = TimeSpan.FromMilliseconds(1000),
                HoverPushout = 8,
            },
        ];
    }

    private void InitializeChartLayout()
    {
        YAxis =
        [
            new Axis
            {
                ShowSeparatorLines = true,
                SeparatorsPaint = new SolidColorPaint(new SKColor(0xE5, 0xE7, 0xEB), 1),
                TicksPaint = new SolidColorPaint(new SKColor(0x9CA3AF), 1),
                SubticksPaint = new SolidColorPaint(new SKColor(0xD1D5DB), 1),
                LabelsPaint = new SolidColorPaint(new SKColor(0x6B7280)),
                NamePaint = new SolidColorPaint(new SKColor(0x374151)),
                TextSize = 12,
                MinStep = 50, // 确保Y轴标签间距合理
                Labeler = value => (long)value + "次",
                NameTextSize = 14,
                NamePadding = new Padding(0, 0, 0, 10),
            },
        ];

        ScrollableAxes =
        [
            new Axis
            {
                ShowSeparatorLines = true,
                SeparatorsPaint = new SolidColorPaint(new SKColor(0xF3, 0xF4, 0xF6), 1),
                TicksPaint = new SolidColorPaint(new SKColor(0x9CA3AF), 1),
                SubticksPaint = null,
                LabelsPaint = new SolidColorPaint(new SKColor(0x6B7280)),
                TextSize = 11,
                MinStep = 10, // X轴时间间距
                Labeler = value =>
                {
                    var timeOffset = DateTime.Now.AddMinutes(-500 + value);
                    return timeOffset.ToString("HH:mm");
                },
            },
        ];

        // 改进滚动区域的视觉效果
        Thumbs =
        [
            new RectangularSection
            {
                Fill = new SolidColorPaint(new SKColor(0x4F, 0x46, 0xE5, 0x20)),
                Stroke = new SolidColorPaint(new SKColor(0x4F, 0x46, 0xE5, 0x60), 2),
            },
        ];

        var auto = Margin.Auto;
        Margin = new Margin(60, auto, 40, 60); // 增加边距以适应标签
    }

    private async Task LoadDashboardDataAsync()
    {
        try
        {
            var dashboardData = await _apiClient.StatisticControllerApi.GetDashboardDataAsync();

            if (dashboardData != null)
            {
                // Update UI on main thread
                Application.Current.Dispatcher.Invoke(() =>
                {
                    UpdateDashboardData(dashboardData);
                });
            }
        }
        catch (Exception ex)
        {
            // Log error and continue with local data
            System.Diagnostics.Debug.WriteLine($"Failed to load dashboard data: {ex.Message}");
        }
    }

    private void UpdateDashboardData(DashboardData data)
    {
        // Update statistics cards
        if (data.TransferredFiles != null)
        {
            TransferredFilesCount = data.TransferredFiles.Current.ToString();
            TransferredFilesChange = FormatChangePercentage(data.TransferredFiles.ChangePercentage);

            // Update dynamic properties for transferred files
            TransferredFilesChangeText = FormatChangePercentage(
                data.TransferredFiles.ChangePercentage
            );
            if (data.TransferredFiles.ChangePercentage > 0)
            {
                TransferredFilesChangeColor = "#22C55E"; // Green for positive
                TransferredFilesChangeIcon = "ArrowUp16";
            }
            else if (data.TransferredFiles.ChangePercentage < 0)
            {
                TransferredFilesChangeColor = "#EF4444"; // Red for negative
                TransferredFilesChangeIcon = "ArrowDown16";
            }
            else
            {
                TransferredFilesChangeColor = "#6B7280"; // Gray for zero
                TransferredFilesChangeIcon = "Subtract16";
            }
        }

        if (data.TotalCapacity != null)
        {
            TotalCapacity = StringFormat.FormatSize(data.TotalCapacity.Current);
            TotalCapacityChange = FormatChangePercentage(data.TotalCapacity.ChangePercentage);

            // Update dynamic properties for total capacity
            TotalCapacityChangeText = FormatChangePercentage(data.TotalCapacity.ChangePercentage);
            if (data.TotalCapacity.ChangePercentage > 0)
            {
                TotalCapacityChangeColor = "#22C55E"; // Green for positive
                TotalCapacityChangeIcon = "ArrowUp16";
            }
            else if (data.TotalCapacity.ChangePercentage < 0)
            {
                TotalCapacityChangeColor = "#EF4444"; // Red for negative
                TotalCapacityChangeIcon = "ArrowDown16";
            }
            else
            {
                TotalCapacityChangeColor = "#6B7280"; // Gray for zero
                TotalCapacityChangeIcon = "subtract16";
            }
        }

        if (data.ActiveShares != null)
        {
            ActiveShares = data.ActiveShares.Current.ToString();
            ActiveSharesChange = FormatChangePercentage(data.ActiveShares.ChangePercentage);

            // Update dynamic properties for active shares
            ActiveSharesChangeText = FormatChangePercentage(data.ActiveShares.ChangePercentage);
            if (data.ActiveShares.ChangePercentage > 0)
            {
                ActiveSharesChangeColor = "#22C55E"; // Green for positive
                ActiveSharesChangeIcon = "ArrowUp16";
            }
            else if (data.ActiveShares.ChangePercentage < 0)
            {
                ActiveSharesChangeColor = "#EF4444"; // Red for negative
                ActiveSharesChangeIcon = "ArrowDown16";
            }
            else
            {
                ActiveSharesChangeColor = "#6B7280"; // Gray for zero
                ActiveSharesChangeIcon = "subtract16";
            }
        }

        // Update storage utilization
        if (data.StorageUtilization != null)
        {
            StorageUtilizationPercentage = data.StorageUtilization.Percentage;
            StorageUtilizationText =
                $"{StringFormat.FormatSize(data.StorageUtilization.UsedSpace)} / {StringFormat.FormatSize(data.StorageUtilization.TotalSpace)}";
        }

        // Update transfer activity chart
        if (data.TransferActivity != null && data.TransferActivity.Count > 0)
        {
            UpdateTransferActivityChart(data.TransferActivity);
        } // Update file type distribution pie chart
        if (data.FileTypeDistribution != null && data.FileTypeDistribution.Count > 0)
        {
            UpdateFileTypeDistributionChart(data.FileTypeDistribution);
        }
        else
        {
            // 如果后端没有文件类型分布数据，则使用本地数据
            UpdatePieSeriesFromLocalData();
        }
    }

    private void UpdateTransferActivityChart(List<TransferActivityPoint> transferActivity)
    {
        _downloadValues.Clear();
        _uploadValues.Clear();

        for (int i = 0; i < transferActivity.Count; i++)
        {
            var point = transferActivity[i];
            _downloadValues.Add(new ObservablePoint(i, point.DownloadCount));
            _uploadValues.Add(new ObservablePoint(i, point.UploadCount));
        }
    }

    // 新增平滑更新数据的方法
    private async Task UpdateChartDataSmoothly(List<TransferActivityPoint> newData)
    {
        if (newData == null || newData.Count == 0)
            return;

        // 平滑动画更新数据
        await Task.Run(async () =>
        {
            var step = 50; // 更新间隔毫秒
            var totalSteps = 20; // 总动画步数

            for (int animationStep = 0; animationStep <= totalSteps; animationStep++)
            {
                var progress = (double)animationStep / totalSteps;

                Application.Current.Dispatcher.Invoke(() =>
                {
                    for (int i = 0; i < Math.Min(newData.Count, _downloadValues.Count); i++)
                    {
                        var currentDownload = _downloadValues[i].Y ?? 0;
                        var targetDownload = newData[i].DownloadCount;
                        var newDownloadValue =
                            currentDownload + (targetDownload - currentDownload) * progress;

                        var currentUpload = _uploadValues[i].Y ?? 0;
                        var targetUpload = newData[i].UploadCount;
                        var newUploadValue =
                            currentUpload + (targetUpload - currentUpload) * progress;

                        _downloadValues[i] = new ObservablePoint(i, newDownloadValue);
                        _uploadValues[i] = new ObservablePoint(i, newUploadValue);
                    }
                });

                if (animationStep < totalSteps)
                    await Task.Delay(step);
            }
        });
    }

    private void UpdateFileTypeDistributionChart(List<FileCategoryModel> fileCategories)
    {
        var newPieSeries = new List<ISeries>();
        var totalFiles = fileCategories.Sum(f => f.FileCount);

        if (totalFiles == 0)
        {
            // Keep default pie chart if no data
            return;
        }

        var colorMap = new Dictionary<FileCategoryModel.FileTypeEnum, SKColor[]>
        {
            {
                FileCategoryModel.FileTypeEnum.IMAGE,
                [new SKColor(0x6366F1), new SKColor(0x4F46E5)]
            },
            {
                FileCategoryModel.FileTypeEnum.DOCUMENT,
                [new SKColor(0x06B6D4), new SKColor(0x0891B2)]
            },
            {
                FileCategoryModel.FileTypeEnum.VIDEO,
                [new SKColor(0x10B981), new SKColor(0x059669)]
            },
            {
                FileCategoryModel.FileTypeEnum.AUDIO,
                [new SKColor(0xF59E0B), new SKColor(0xD97706)]
            },
            {
                FileCategoryModel.FileTypeEnum.OTHER,
                [new SKColor(0x9CA3AF), new SKColor(0x6B7280)]
            },
        };

        var nameMap = new Dictionary<FileCategoryModel.FileTypeEnum, string>
        {
            { FileCategoryModel.FileTypeEnum.IMAGE, "图片" },
            { FileCategoryModel.FileTypeEnum.DOCUMENT, "文档" },
            { FileCategoryModel.FileTypeEnum.VIDEO, "视频" },
            { FileCategoryModel.FileTypeEnum.AUDIO, "音频" },
            { FileCategoryModel.FileTypeEnum.OTHER, "其他" },
        };

        foreach (var category in fileCategories)
        {
            if (category.FileCount > 0 && category.FileType.HasValue)
            {
                var percentage = (double)category.FileCount / totalFiles * 100;
                var colors = colorMap.GetValueOrDefault(
                    category.FileType.Value,
                    [new SKColor(0x9CA3AF), new SKColor(0x6B7280)]
                );
                var name = nameMap.GetValueOrDefault(category.FileType.Value, "未知文件");

                newPieSeries.Add(
                    new PieSeries<double>
                    {
                        Name = name,
                        Values = [percentage],
                        Fill = new RadialGradientPaint(colors),
                        Stroke = new SolidColorPaint(SKColors.White, 2),
                        DataLabelsPaint = new SolidColorPaint(SKColors.White),
                        DataLabelsSize = 12,
                        DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
                        DataLabelsFormatter = point => $"{name} {point.Model:F1}%",
                        AnimationsSpeed = TimeSpan.FromMilliseconds(1000),
                        HoverPushout = 8,
                        ToolTipLabelFormatter = point => $"{category.FileCount}个",
                    }
                );
            }
        }

        PieSeries = newPieSeries.ToArray();
    }

    private static string FormatChangePercentage(double changePercentage)
    {
        var sign = changePercentage >= 0 ? "+" : "";
        return $"{sign}{changePercentage:F1}%";
    }

    [RelayCommand]
    private async Task RefreshDashboardData()
    {
        await LoadDashboardDataAsync();
    }

    /// <summary>
    /// 刷新饼图数据，可以在上传或下载完成后调用
    /// </summary>
    public void RefreshPieChart()
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            UpdatePieSeriesFromLocalData();
        });
    }

    [ObservableProperty]
    private ISeries[] _series = [];

    [ObservableProperty]
    private ISeries[] _pieSeries = [];

    [ObservableProperty]
    private Axis[] _yAxis = [];

    [ObservableProperty]
    private Axis[] _scrollableAxes = [];

    [ObservableProperty]
    private Margin _margin = new Margin();

    [ObservableProperty]
    private RectangularSection[] _thumbs = [];

    [ObservableProperty]
    private ObservableCollection<HistoryItem> _recentTransfers = [];

    [ObservableProperty]
    private bool _isConnected = false;

    [ObservableProperty]
    private string _connectionStatus = "未知";

    [ObservableProperty]
    private string _connectionStatusDetail = "...";

    [ObservableProperty]
    private bool _isRealTimeUpdateEnabled = false;

    partial void OnIsRealTimeUpdateEnabledChanged(bool value)
    {
        if (value)
            StartRealTimeUpdates();
        else
            StopRealTimeUpdates();
    }

    [RelayCommand]
    private void ChartUpdated(ChartCommandArgs args)
    {
        var chart = (ICartesianChartView)args.Chart;
        var x = chart.XAxes.First();

        var thumb = Thumbs[0];
        thumb.Xi = x.MinLimit;
        thumb.Xj = x.MaxLimit;
    }

    [RelayCommand]
    private void PointerDown(PointerCommandArgs args) => _isDown = true;

    [RelayCommand]
    private void PointerMove(PointerCommandArgs args)
    {
        if (!_isDown)
            return;

        var chart = (ICartesianChartView)args.Chart;
        var pos = chart.ScalePixelsToData(args.PointerPosition);

        var thumb = Thumbs[0];
        var range = thumb.Xj - thumb.Xi;

        thumb.Xi = pos.X - range / 2;
        thumb.Xj = pos.X + range / 2;

        ScrollableAxes[0].MinLimit = thumb.Xi;
        ScrollableAxes[0].MaxLimit = thumb.Xj;
    }

    [RelayCommand]
    private void PointerUp(PointerCommandArgs args) => _isDown = false;

    [RelayCommand]
    private void NavigateToUpload()
    {
        _navigationWindow.Navigate(typeof(Views.Pages.UploadPage));
    }

    [RelayCommand]
    private void NavigateToMyShare()
    {
        if (_serviceProvider.GetService<ManagementViewModel>() is { } msVm)
        {
            msVm.SelectedTabIndex = 1;
        }
        _navigationWindow.Navigate(typeof(Views.Pages.ManagementPage));
    }

    [RelayCommand]
    private async Task TestNetworkConnection()
    {
        IsConnected = false;
        ConnectionStatus = "检测中...";
        ConnectionStatusDetail = ConnectionStatus;
        try
        {
#if DEBUG
            await Task.Delay(1500);
#endif
            var result = await _apiClient.ConnectionControllerApi.TestConnectionAsync();
            IsConnected = result;
            ConnectionStatus = result ? "连接正常" : "连接失败";
            ConnectionStatusDetail = ConnectionStatus;
        }
        catch (Exception ex)
        {
            ConnectionStatus = "连接错误";
            ConnectionStatusDetail = ex.Message;
            IsConnected = false;
        }
    }

    private async Task InitializeNetworkStatus()
    {
        await TestNetworkConnection();
    }

    private void StartRealTimeUpdates()
    {
        if (_realTimeUpdateTimer != null)
            return;

        _realTimeUpdateTimer = new System.Timers.Timer(5000); // 5 seconds interval
        _realTimeUpdateTimer.Elapsed += async (sender, e) =>
        {
            try
            {
                await LoadDashboardDataAsync();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Real-time update failed: {ex.Message}");
            }
        };
        _realTimeUpdateTimer.AutoReset = true;
        _realTimeUpdateTimer.Enabled = true;
    }

    private void StopRealTimeUpdates()
    {
        if (_realTimeUpdateTimer != null)
        {
            _realTimeUpdateTimer.Stop();
            _realTimeUpdateTimer.Dispose();
            _realTimeUpdateTimer = null;
        }
    }

    // Cleanup method to be called when the view model is disposed
    public void Dispose()
    {
        StopRealTimeUpdates();
    }
}
